fn main() {
    {
        // String 表示命名空间， from为String命名空间下的函数
        let mut s = String::from("hello"); // 从此处开始s有效
        s.push_str(",world!");
        println!("{}", s);
    } // 作用域已经结束
    // s 不再有效

    // 由于5是已知大小，所以x,y都在栈中，相当于放了两个5在栈中
    let x = 5;
    let y = x;
    println!("x:{x},y:{y}");

    // ss 只拷贝了s的指针等栈上数据，并没有复制指针指向的堆数据，浅拷贝
    let s = String::from("123");
    // s此时引用无效，s被移动到了ss
    // let ss = s;

    // 使用clone完成深拷贝
    let ss = s.clone();
    println!("s:{s},ss:{ss}");

    let num = 5;
    test1(num);
    // 因为5实现的Copy trait，所以这里可以使用
    println!("after test1:{num}");

    let s = String::from("tests");
    // test2(s);
    // 此处报错，原理同上
    // println!("after test2:{s}")

    // 不可变引用：传入s的引用，s的所有权不会转移，后续还能继续使用
    test3(&s);
    println!("after test3:{s}");

    // 可变引用：change_name将改变所借用的值
    let mut s = String::from("张三");
    change_name(&mut s);
    println!("after change_name:{s}");

    // error:一个值不能有多个连续的可变引用
    // let r1 = &mut s;
    // let r2 = &mut s;
    // println!("{},{}", r1, r2);

    // error:不能同一时间（在一个作用域内）对一个变量创建不可变和可变引用
    // let r1 = &mut s;
    // let r2 = &s;
    // println!("{},{}", r1, r2);

    // correct:可以同一时间（在一个作用域内）对一个变量多个不可变引用
    let r1 = &s;
    let r2 = &s;
    println!("{},{}", r1, r2);

    // 可以在不同作用域内
    let r1 = &mut s;
    println!("{}", r1);// r1 在此之后离开作用域
    let r2 = &mut s;
    println!("{}", r2);

    test5();

    let mut s = String::from("you are a good boy");
    let first = first_world(&s);
    // first 后面还会打印，所以为失效。s.clear尝试获取一个可变引用，和不可变引用冲突，会报错
    // s.clear();
    // println!("{}", first);

    let first = first_world2("hello world");
    println!("{}", first);
    let first = first_world2(&s[4..6]);
    println!("{}", first);
    // 等价于整个String的slice
    let first = first_world2(&s);
    println!("{}", first);
}

fn change_name(name: &mut String) {
    name.push_str("和李四");
    println!("{name}")
}

fn test1(s : i32) {
    println!("test1 print :{s}")
}

fn test2(s : String) {
    println!("test2 print {s}")
}

// s是一个引用
fn test3(s : &String) {
    println!("test3 print {s}")
}

// 离开方法时s的值已经被释放，&s会变成悬垂引用，因此编译无法通过
// fn test4() -> &String {
//     let s = String::from("hello");
//     &s
// }

fn test5() {
    let s = String::from("hello world!");
    let hello = &s[..5];// 等价与&s[0..5]
    let world = &s[6..];// 等价与&s[6..s.len()]
    println!("{},{}", hello, world);
}

fn first_world(s : &String) -> &str {
    let bytes = s.as_bytes();
    for (i, &item) in bytes.iter().enumerate() {
        // 如果是空格
        if item == b' ' {
            return &s[..i];
        }
    }

    // 返回整个字符串
    &s[..]
}

// 使用&str,可以支持字面量和字符串，更加推荐
fn first_world2(s : &str) -> &str {
    let bytes = s.as_bytes();
    for (i, &item) in bytes.iter().enumerate() {
        // 如果是空格
        if item == b' ' {
            return &s[..i];
        }
    }

    // 返回整个字符串
    &s[..]
}